package cn.tedu.luban.worker.main.service;

import cn.tedu.luban.account.api.AccountApi;
import cn.tedu.luban.account.protocol.dto.AccountDTO;
import cn.tedu.luban.account.protocol.param.AccountCreateParam;
import cn.tedu.luban.attach.api.AttachApi;
import cn.tedu.luban.attach.protocol.dto.AttachDTO;
import cn.tedu.luban.attach.protocol.param.AttachUpdateParam;
import cn.tedu.luban.attach.protocol.query.AttachQuery;
import cn.tedu.luban.passport.protocol.jwt.UserPrinciple;
import cn.tedu.luban.passport.sdk.security.LubanSecurityContext;
import cn.tedu.luban.worker.common.enums.AuditStatusEnum;
import cn.tedu.luban.worker.common.enums.WorkerResultEnum;
import cn.tedu.luban.worker.main.converter.WorkerConverter;
import cn.tedu.luban.worker.main.repository.WorkerAreaRepository;
import cn.tedu.luban.worker.main.repository.WorkerAuditLogRepository;
import cn.tedu.luban.worker.main.repository.WorkerCategoryRepository;
import cn.tedu.luban.worker.main.repository.WorkerRepository;
import cn.tedu.luban.worker.protocol.bo.*;
import cn.tedu.luban.worker.protocol.param.AuditSubmitParam;
import cn.tedu.luban.worker.protocol.param.IdCardParam;
import cn.tedu.luban.worker.protocol.param.WorkerParam;
import cn.tedu.luban.worker.protocol.param.WorkerRegistParam;
import cn.tedu.luban.worker.protocol.query.WorkerListQuery;
import com.tedu.inn.protocol.ListRecordTotalBO;
import com.tedu.inn.protocol.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;

@Service
@Slf4j
public class WorkerService {

    /**
     * 师傅入驻业务方法
     * @param param 入驻参数
     * @return 入驻成功的workerId
     */
    public Long workerCreate(WorkerRegistParam param) throws BusinessException {

        // 1.获取登录的用户userId
        Long userId= getUserId();
        param.setUserId(userId);
        // 2.校验参数  身份证信息（身份证和人名） 
        checkIdCard(param);
        // 3.保存worker信息到数据库
        Long workerId = saveWorker(param);
        // 4.保存worker_area信息到数据库
        saveWorkerArea(param);
        // 5.保存worker_category信息到数据库
        saveWorkerCategory(param);
        // 6.解析param中图片信息，绑定师傅业务数据
        bindPic(param,workerId);

        return workerId;
    }

    /**
     * 师傅详情业务方法
     */
    public FrontWorkerBO workerDetail() throws BusinessException {
        // 1.获取登录的用户userId
        Long userId = getUserId();
        // 2.根据userId查询数据库获取worker信息
        FrontWorkerBO workerBO = workerRepository.getWorkerByUserId(userId);
        // 判断 FrontWorkerBO 是否为空
        // 因为仓储层转化器习惯 workerBO不可能为 null，所以用其属性判断
        if(workerBO.getId() == null){
            log.info("没有查询到师傅信息");
            // 登录用户没有入驻师傅， 审核状态 3
            workerBO.setAuditStatus(AuditStatusEnum.UNCREATED.getValue());
        }else{
            // 3.补充师傅区域与种类信息
            log.info("师傅不为空，补充区域和种类信息");
            putAreaAndCategories(workerBO);
            // 获取审核状态
            Integer auditStatus = workerBO.getAuditStatus();
            // 4.判断审核状态 2 1 0
            if(auditStatus == 0){
                log.info("审核被驳回，补充驳回原因");
                // 调用仓储层workerAuditRepository，获取驳回原因(最后一次)，补充到workerBO中
                String rejectReason = getLastRejectReason(userId);
                workerBO.setRejectReason(rejectReason);
            }else if(auditStatus == 1){
                log.info("审核通过，查询账户余额");
                // 5.rpc调用账户中心account，查询账户余额，补充到workerBO中
                AccountDTO account = accountApi.getAccount(userId);
                FrontAccountBO accountBO = new FrontAccountBO();
                // 账户余额 只有一个属性，不涉及转换
                accountBO.setTotalAmount(account.getTotalAmount());
                workerBO.setFrontAccountBO(accountBO);
            }
        }
        return workerBO;
    }

    /**
     * 获取最后一次的驳回原因
     */
    private String getLastRejectReason(Long userId) throws BusinessException {
        // 获取userID所有的审核信息
        List<AdminAuditBO> auditLogs = workerAuditLogRepository.findAuditLogs(userId);
        if(CollectionUtils.isEmpty(auditLogs)){
            // 自定义枚举， AUDIT_STATUS_ERROR
            throw new BusinessException("1004","驳回原因为空");
        }else{
            AdminAuditBO adminAuditBO = CollectionUtils.lastElement(auditLogs);
            String rejectReason = adminAuditBO.getRejectReason()+"[详细原因: "+adminAuditBO.getRemark()+"]";
            return rejectReason;
        }
    }

    private void putAreaAndCategories(FrontWorkerBO workerBO) {
        // 1.根据共同的userId 完成查询
        Long userId = workerBO.getUserId();
        // 2.查询区域和种类信息
        List<WorkerAreaBO> areaBOs = workerAreaRepository.findAreas(userId);
        List<WorkerCategoryBO> categoryBOs = workerCategoryRepository.findCategories(userId);
        // 3.补充到workerBO中
        workerBO.setWorkerAreaBOList(areaBOs);
        workerBO.setWorkerCategoryBOList(categoryBOs);

    }

    @Autowired
    private AttachApi attachApi;

    @Autowired
    private WorkerConverter workerConverter;

    /**
     * 解析param中图片信息，绑定师傅业务数据
     * @param param 入驻参数
     * @param workerId  workerId
     */
    private void bindPic(WorkerRegistParam param, Long workerId) throws BusinessException {

        // 准备param中图片信息
        List<IdCardParam> idCards = param.getAttachList();

        // 调用转换器，将IdCardParam转换为AttachUpdateParam
        List<AttachUpdateParam> attachUpdateParams =
                workerConverter.assembleAttachParam(idCards, 100, workerId.intValue());

        // 远程调用，更新图片信息
        try {
            attachApi.batchUpdateAttachByIdList(attachUpdateParams);
        }catch (Exception e) {
            // 可能出现rpc异常，需要捕获处理
            throw new BusinessException(WorkerResultEnum.ATTACH_UPDATE_FAILED);
        }

    }

    @Autowired
    private WorkerCategoryRepository workerCategoryRepository;

    /**
     * 保存worker_category信息到数据库
     * @param param 入驻参数
     */
    private void saveWorkerCategory(WorkerRegistParam param) {
        // 使用user_id绑定师傅的业务字段 做条件  删除新增时已有的师傅区域信息
        workerCategoryRepository.deleteByUserId(param.getUserId());
        // 新增师傅区域信息(批量) insert into worker_category(user_id,...) values(xxx,...),(xxx,...);
        workerCategoryRepository.saveWorkerCategories(param);
    }

    @Autowired
    private WorkerAreaRepository workerAreaRepository;

    /**
     * 保存worker_area信息到数据库
     * @param param 入驻参数
     */
    private void saveWorkerArea(WorkerRegistParam param) {
        // 使用user_id绑定师傅的业务字段 做条件  删除新增时已有的师傅区域信息
        workerAreaRepository.deleteByUserId(param.getUserId());
        // 新增师傅区域信息(批量) insert into worker_area(user_id,...) values(xxx,...),(xxx,...);
        workerAreaRepository.saveWorkerAreas(param);
    }

    @Autowired
    private WorkerRepository workerRepository;
    /**
     * 保存worker信息到数据库
     * @param param 入驻参数
     * @return workerId
     */
    private Long saveWorker(WorkerRegistParam param) {
        // 幂等逻辑：同一个登录用户，绑定多个师傅，最终只有一个师傅信息
        // 利用师傅绑定userId,先删除历史数据 :delete from worker where user_id = xxx;
        workerRepository.deleteByUserId(param.getUserId());
        // 新增师傅 insert into worker(user_id,...) values(xxx,...);
        Long workerId = workerRepository.save(param);
        return workerId;
    }

    /**
     * 校验参数  身份证信息（身份证和人名）
     * @param param 入驻参数
     */
    private void checkIdCard(WorkerRegistParam param) {
        // 使用真是的姓名和身份证号，验证是否合法： 对接公安系统或者大场接口（认证宝）
        // 假设身份证号和姓名都合法，则返回true
        // 假设身份证号和姓名不合法，则抛出异常
        // 身份证脱敏处理（110101200808081234 -> 110101****1234）
    }

    /**
     * 获取登录的用户userId
     * @return userId
     */
    private Long getUserId() throws BusinessException {
        UserPrinciple user = LubanSecurityContext.getLoginToken();
        if(user == null){
            throw new BusinessException(WorkerResultEnum.USER_TOKEN_VERIFY_FAILED);
        }
        return user.getId();
    }

    /**
     * 师傅审核列表业务方法
     */
    public ListRecordTotalBO<AdminWorkerBO> workerAuditList(WorkerListQuery query) {
        // 1.auditStatus的数据封装（前端未传参 auditStatus=[0,2]）
        putAuditStatusForApproved(query);
        // 2.利用query条件查询数据库获取worker的 total信息
        Long total = workerRepository.countWorker(query);
        // 判断 total是否为0
        ListRecordTotalBO<AdminWorkerBO> listTotal= null;
        if(total == 0){
            // 查不到 返回一个空分页数据
            listTotal = new ListRecordTotalBO<>(null,total);
        }else{
            // 3.查到 分页数据
            List<AdminWorkerBO> list =  workerRepository.findPageWorkers(query);
            // 4. 补充区域和种类信息
            putWorkerAreasAndCategories(list);

            listTotal = new ListRecordTotalBO<>(list,total);
        }
        return listTotal;
    }

    /**
     * 补充区域和种类信息
     */
    private void putWorkerAreasAndCategories(List<AdminWorkerBO> list) {
        // 师傅 区域 种类 三表 关联字段 user_id 相同
        for(AdminWorkerBO workerBO : list){
            // 1.根据共同的userId 完成查询
            Long userId = workerBO.getUserId();
            // 2.查询区域和种类信息
            List<WorkerAreaBO> areas = workerAreaRepository.findAreas(userId);// 已定义
            List<String> areaDetails = new ArrayList<>();
            for(WorkerAreaBO area : areas){
                areaDetails.add(area.getAreaDetail());
            }

            List<WorkerCategoryBO> categories = workerCategoryRepository.findCategories(userId);// 已定义
            List<String> categoryDetails = new ArrayList<>();
            for(WorkerCategoryBO category : categories){
                categoryDetails.add(category.getCategoryDetail());
            }
            // 3.补充到workerBO中
            workerBO.setAreaDetails(areaDetails);
            workerBO.setCategoryDetails(categoryDetails);
        }

    }

    /**
     * 审核状态数据封装（前端未传参 auditStatus=[0,2]）
     */
    private void putAuditStatusForApproved(WorkerListQuery query) {
        List<Integer> auditStatus = query.getAuditStatus();
        if(CollectionUtils.isEmpty(auditStatus)){
            auditStatus.add(0);
            auditStatus.add(2);
        }
        log.info("补充完成之后的 query:{}",query);
    }

    @Autowired
    private WorkerAuditLogRepository workerAuditLogRepository;

    public AdminWorkerBO workerAuditDetail(Long userId) throws BusinessException {
        // 1.根据userId查询数据库获取worker信息
        AdminWorkerBO workerBO = workerRepository.findAdminWorker(userId);
        // 判断 workerBO 是否为空
        if(workerBO.getId() == null){
            log.info("没有查询到师傅信息");
            throw new BusinessException(WorkerResultEnum.WORKER_NOT_FOUND);
        }

        // 2.补充区域、3.补充种类信息
        putWorkerAreasAndCategories(workerBO);
        // 4.补充审核信息
        List<AdminAuditBO> auditLogs = workerAuditLogRepository.findAuditLogs(userId);
        workerBO.setWorkerAuditLogs(auditLogs);

        // 5.补充图片信息
        putPictureUrls(workerBO);

        return workerBO;
    }



    private void putPictureUrls(AdminWorkerBO workerBO) throws BusinessException {
        // 1. 构建查询对象
        AttachQuery attachQuery = new AttachQuery();
        attachQuery.setBusinessId(workerBO.getId().intValue());
        attachQuery.setBusinessType(100);
        // 2. 调用远程接口，获取图片信息
        List<AttachDTO> dtos = attachApi.getAttachInfoByParam(attachQuery);
        // 3. 处理查询结果
        List<String> urls = new ArrayList<>();

        if(CollectionUtils.isEmpty(dtos)){
            // 出现空图片,异常处理
            throw new BusinessException(WorkerResultEnum.ATTACH_UPDATE_FAILED);
        }else{
            for(AttachDTO dto : dtos){
                String fileUuid = dto.getFileUuid();
                String url = "http://localhost:8092/static/" + fileUuid;
                urls.add(url);
            }
        }
        // 将查询结果填补到workerBO中
        workerBO.setAttachInfo(urls);
    }

    /**
     * 补充区域和种类信息
     * 集合中只有一个workerBO，进行封装
     */
    private void putWorkerAreasAndCategories(AdminWorkerBO workerBO) {
        List<AdminWorkerBO> list = new ArrayList<>();
        list.add(workerBO);
        putWorkerAreasAndCategories(list);
    }


    public Long auditSubmit(AuditSubmitParam param) throws BusinessException {
        // 1.获取workerId,查询师傅的BO数据
        AdminWorkerBO adminWorker = workerRepository.findAdminWorker(param.getWorkerId());
        // 判断是否为空
        if(adminWorker.getId() == null){ // 抛出异常
            throw new BusinessException(WorkerResultEnum.WORKER_NOT_FOUND);
        }
        // 2.师傅不为空，获取当前师傅状态，判断流转是否正常
        Integer currentAuditStatus = adminWorker.getAuditStatus();
        Integer targetAuditStatus = param.getAuditStatus();
        checkAuditStatusTransfer(currentAuditStatus,targetAuditStatus);

        // 3.新增审核日志记录 worker_audit_log insert
        param.setUserId(param.getWorkerId());
        param.setUsername(adminWorker.getRealName());
        Long auditId = workerAuditLogRepository.save(param);

        // 4.更新师傅审核状态 worker update worker set audit_status=#{auditStatus} ... where user_id=#{userId}
        // 仓储入参 封装了一个WorkerParam对象
        WorkerParam workerParam = new WorkerParam();
        workerParam.setAuditStatus(targetAuditStatus);
        workerParam.setUserId(param.getWorkerId());
        workerRepository.updateAuditStatus(workerParam);

        // 5. 认证通过，创建账户
        Integer certStatus = adminWorker.getCertStatus();// 认证状态
        if(targetAuditStatus == 1 && certStatus==0){
            // 修改师傅的认证状态
            workerParam.setCertStatus(1);
            workerRepository.updateCertStatus(workerParam);
            // 调用账户中心，创建账户
            bindAccount(adminWorker);
        }
        return auditId;
    }

    @Autowired
    private AccountApi accountApi;

    private void bindAccount(AdminWorkerBO adminWorker) {
        AccountCreateParam accountCreateParam = new AccountCreateParam();
        accountCreateParam.setUserId(adminWorker.getUserId());
        accountCreateParam.setUserName(adminWorker.getRealName());
        accountCreateParam.setUserPhone(adminWorker.getPhone());
        accountApi.createAccount(accountCreateParam);
    }

    private void checkAuditStatusTransfer(Integer currentAuditStatus, Integer targetAuditStatus) throws BusinessException {
        /*
            0: 驳回   1: 审核通过    2: 未审核
                1->0 false 1->2 false 1->1 false
                2->0 true 2->2 true 2->1 true
                0->1 true 0->2 true 0->0 true
         */
        // 只有状态是通过 就不允许提交审核
        if(currentAuditStatus == 1){
            throw new BusinessException(WorkerResultEnum.AUDIT_STATUS_TRANSFER_ERROR);
        }
    }


}
























